// 该头文件提供一些方便于进行搜索引擎项目制作的工具
#pragma once
#include <iostream>
#include <random>
#include <vector>
#include <string>
#include <fstream>
#include <boost/algorithm/string.hpp>
#include <atomic>
#include "Log.hpp"
#include "../cppjieba/Jieba.hpp"
#include <nlohmann/json.hpp>

using namespace std;

extern Log lg;

namespace search_utility
{
    class FileUtility
    {
    public:
        // 执行文件读取的操作，把文件当中的信息存储到输出字符串当中
        static bool ReadFile(const string &file_path, string *output)
        {
            ifstream in(file_path, ios::in);
            if (!in.is_open())
            {
                lg(Warning, "open file %s error", file_path.c_str());
                return false;
            }
            string line;
            while (getline(in, line))
                *output += line;
            in.close();
            return true;
        }
    };

    class StringUtil
    {
    public:
        static void Split(const string &line, vector<string> *res, const string &sep)
        {
            boost::split(*res, line, boost::is_any_of(sep), boost::token_compress_on);
        }
    };

    const char *const DICT_PATH = "./dict/jieba.dict.utf8";
    const char *const HMM_PATH = "./dict/hmm_model.utf8";
    const char *const USER_DICT_PATH = "./dict/user.dict.utf8";
    const char *const IDF_PATH = "./dict/idf.utf8";
    const char *const STOP_WORD_PATH = "./dict/stop_words.utf8";

    class JiebaUtil
    {
    public:
        static void CutString(const string &src, vector<string> *out)
        {
            JiebaUtil::jieba.CutForSearch(src, *out);
        }

    private:
        static cppjieba::Jieba jieba;
    };
    cppjieba::Jieba JiebaUtil::jieba(DICT_PATH, HMM_PATH, USER_DICT_PATH, IDF_PATH, STOP_WORD_PATH);
}

class UUIDHelper 
{
public:
    static string uuid() 
    {
        random_device rd;
        mt19937_64 gernator(rd());
        uniform_int_distribution<int> distribution(0, 255);
        stringstream ss;
        for (int i = 0; i < 8; i++) 
        {
            ss << setw(2) << setfill('0') << hex << distribution(gernator) ;
            if (i == 3 || i == 5 || i == 7) 
                ss << "-";
        }
        static atomic<size_t> seq(1);
        size_t num = seq.fetch_add(1);
        for (int i = 7; i >= 0; i--) 
        {
            ss << setw(2) << setfill('0') << hex << ((num>>(i*8)) & 0xff);
            if (i == 6) 
                ss << "-";
        }
        return ss.str();
    }
};

class DataBaseConf
{
    using json = nlohmann::json;
public:
    struct DatabaseConfig 
    {
        string host;
        string username;
        string password;
        string dbName;
    };

    // 使用静态局部变量确保只初始化一次
    static DatabaseConfig& getDatabaseConfig(const string& jsonfilepath)
    {
        static DatabaseConfig config;
        static bool isFirstTime = true;
        if (isFirstTime)
        {
            isFirstTime = false;
            // 从环境变量里面获取
            if(getenv("DB_HOST") == nullptr)
            {
                ifstream configFile(jsonfilepath);
                if (!configFile.is_open())
                {
                    cout << "Failed to open db_config.json" << endl;
                }
                json jsonData;
                configFile >> jsonData;
                config.host = jsonData["database"]["host"].get<string>();
                config.username = jsonData["database"]["username"].get<string>();
                config.password = jsonData["database"]["password"].get<string>();
                config.dbName = jsonData["database"]["database_name"].get<string>();
                configFile.close();
            }
            else  
            {
                // 如果获取到了，就说明此时是Dockerfile环境
                config.host = getenv("DB_HOST");
                config.username = getenv("DB_USER");
                config.password = getenv("DB_PASSWORD");
                config.dbName = getenv("DB_NAME");
            }
        }
        return config;
    }
};
